home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
yase.arc
/
FILEPRIM.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-12-13
|
10KB
|
285 lines
******************************************************************
* COPYRIGHT (C) 1986 by Donald Krantz and James Stanley
* - Note: This is a real, live, actual, registered copyright,
* and should be treated as such. This source code is from
* the book "68000 Assembly Language", Krantz and Stanley,
* Addison-Wesley Publishing Company, Reading, MA, 1986.
*
* Permission granted by the authors for non-commercial use
* in programs released to the public domain, as long as this
* copyright notice remains attached and visible.
*
***************************************************************
* File Primitive Operations - CP/M-68K
*
* All routines interface to CP/M-68K files. FCB and FILE block
* definitions are contained in FCB.H.
#fcb.h
.xdef open,close,fgetc,fputc
* Routines: OPEN Opens a file for input or output.
* Entry: P0.L points to FILE block. P1.L points to
* null-terminated name string. P2.W = 0
* for "File must Exist", nonzero
* for "Create new and erase old".
* Exit: File opened or D0.W = -1
*
* CLOSE Closes a file. Flushes current buffer
* if dirty.
* Entry: P0.L points to FILE block.
* Exit: File closed or D0.W = -1
*
* FGETC Returns next char from file.
* Entry: P0.L points to FILE block.
* Exit: D0.W = char or -1 on error.
*
* FPUTC Writes next char to file.
* Entry: P0.L points to FILE block.
* P1.W is the char to write.
* Exit: D0.W = 0 for success, -1 on failure.
*
*****************************************************************
open:
link a6,#0 * Set stack frame
movem.l d1/d2/a0/a1/a2,-(a7)
bsr parse_name * Parses filename to FCB
tst.w d0 * Check return from PARSE_NAME
bmi exit_open * Exit on error
bsr fillfcb * Set balance of FCB
move.l 8(a6),d1 * Get FCB addr for CP/M calls
tst.w 16(a6) * Open new file or old?
bne make_new * Make new file, erase any old.
must_exist:
move.w #$000f,d0 * CP/M OPEN FILE Function Code
trap #2 * Call CP/M - Open existing file
bra exit_open * Exit
make_new:
move.w #$0013,d0 * CP/M DELETE FILE Function code
trap #2 * Call CP/M - delete any old file
move.w #$0016,d0 * CP/M MAKE FILE Function code
trap #2 * Call CP/M - attempt create
exit_open:
ext.w d0 * Convert CP/M return to our type
movem.l (a7)+,d1/d2/a0/a1/a2
unlk a6 * Restore caller's stack frame
rts
*
*****************************************************************
* PARSE_NAME parses a C name string into CP/M-68K FCB. Uses
* caller's stack frame. Consider this a local procedure to OPEN.
parse_name:
move.l 8(a6),a0 * Pick up FCB address
move.l 12(a6),a1 * Pick up name string
move.w #10,d0 * Loop counter for blank filling
blank_loop:
move.b #' ',1(a0,d0.w) * Blank fill name "backwards"
dbra d0,blank_loop * Continue for 11 bytes
*
cmp.b #':',1(a1) * Check for drivespec
bne no_drive * No drivespec, jump over
move.b (a1),(a0) * Transfer drivespec
and.b #$0f,(a0)+ * Make into 0..16 drivecode
addq.l #2,a1 * Put pointer past drivespec
bra name_xfr * Go transfer name
no_drive:
clr.b (a0)+ * Set default drivecode
name_xfr:
move.w #7,d0 * Start with filename part
name_loop:
move.b (a1)+,d2 * Pickup name character
beq parse_chk * Found a terminal null...
cmp.b #'.',d2 * Look for delimiter
beq ext_xfr * Parse extension
bsr check * Make uppercase & screen chars
tst.b d1 * D1 = -1 for illegal character
bmi parse_err * Exit if CHECK found error
move.b d2,(a0)+ * Put char in FCB
dbra d0,name_loop * Try again
* If we're here, 8 filename chars were found. Skip period.
move.b (a1)+,d2 * Move pointer and check char
cmp.b #'.',d2 * Double check for period
beq ext_xfr * OK, let's continue
bra parse_err * Badly formed name string.
ext_xfr:
move.l 8(a6),a0 * Re-sync FCB pointer
adda #type,a0 * Point at TYPE field
move.w #2,d0 * Three chars only for filetype
ext_loop:
move.b (a1)+,d2 * Pickup filetype char
beq parse_chk * Found terminal null...
bsr check * Make uppercase and screen chars
tst.b d1 * Look for error return
bmi parse_err * Exit if CHECK found error.
move.b d2,(a0)+ * Put filetype char into FCB
dbra d0,ext_loop * Go for next
* If we're here, 3 filetype chars were found. Check for null.
tst.b (a1) * Is it null?
bne parse_err * No, return error
parse_chk:
move.l 8(a6),a0 * Get FCB base addr again
cmp.b #' ',name(a0) * At least one name char?
beq parse_err * Nope, return error.
clr.w d0 * "Good" return code
rts
parse_err:
move.w #-1,d0 * "Bad" return code
rts
*
*****************************************************************
* FILLFCB zeros the non-name portion of the FCB. Local to OPEN.
fillfcb:
move.l 8(a6),a0 * Load FCB base address
adda #extent,a0 * Index past name portion
move.w #dma_buf-extent-1,d0 * Loop count
fill_loop:
clr.b (a0)+ * Load zeros in all FILE fields
dbra d0,fill_loop * Continue for all bytes in FILE
tst.w 16(a6) * Is this a write?
bne fill_exit * Yes, CURCHR is ok as zero.
move.l 8(a6),a0 * Get FCB address again.
move.w #128,curchr(a0) * Mark as "Need to read"
fill_exit:
rts
*
*****************************************************************
* CHECK converts lowercase to uppercase and screens chars CP/M
* considers illegal name characters.
check:
cmp.b #'a',d2 * Check for lowercase first.
blt not_lower * It's less than 'a'
cmp.b #'z',d2 * Less than 'z'?
bgt not_lower * It's greater than 'z'
and.b #$5f,d2 * Makes D2.B uppercase
not_lower:
move.w #18,d1 * 19 illegal name chars
lea bad_chars,a2 * Get name array base
chk_loop:
cmp.b (a2)+,d2 * Test for bad char
beq chk_err * Bad char, return error
dbra d1,chk_loop * Keep trying.
clr.w d1 * "Good" error return
rts * "Good" exit
chk_err:
move.w #-1,d1 * "Bad" error return
rts * "Bad" exit
bad_chars:
dc.b '.:[]()<>=*&,!|?/;+-'
even * Force alignment
*
*****************************************************************
* CLOSE Closes a file. Flushes current buffer if dirty.
close:
link a6,#0 * Setup stack frame
movem.l d1/a0/a1,-(a7) * Save caller's registers
move.l 8(a6),a0 * Pick up FCB base address
bsr put_eof * Add ASCII EOF (^Z)
bmi exit_close * Branch if write failed
move.l d1,a0 * Setup CP/M parameter
move.w #$0010,d0 * CP/M CLOSE FILE function code
trap #2 * Close the file
exit_close:
ext.w d0 * Convert CP/M return to our type
movem.l (a7)+,d1/a0/a1 * Restore caller's registers
unlk a6 * Restore caller's stack frame
rts
*
*****************************************************************
* PUT_EOF fills the end of the current DMA buffer with ^Z
put_eof:
cmp.w #128,curchr(a0) * Check if we need to add another
bne do_rest * record with EOFs. (jump on NO)
tst.w dirty(a0) * look for empty record
beq do_rest * jump if this record empty
bsr write_buf * Flush current record
do_rest:
move.w #127,d0 * Set up number of chars to fill
sub.w curchr(a0),d0 * less current character count
adda curchr(a0),a0 * Get address of first fill char
adda #dma_buf,a0 * Need this too.
put_loop:
move.b #$1a,(a0)+ * Insert character
dbra d0,put_loop * Continue through buffer
bsr write_buf * Flush filled record
rts
*
*****************************************************************
* FPUTC puts a character to a disk file.
fputc:
link a6,#0 * Freeze stack frame
movem.l a0/d1,-(a7) * Save caller's registers
move.l 8(a6),a0 * Grab FCB
cmp.w #128,curchr(a0) * Check for record full
bne just_put * Nope, we're OK.
bsr write_buf * Flush current record
just_put:
move.w curchr(a0),d0 * Get current char count
addq.w #1,curchr(a0) * Bump counter
move.w #-1,dirty(a0) * Make dirty
move.b 13(a6),dma_buf(a0,d0.w) * Save character
movem.l (a7)+,a0/d1 * Restore caller's registers
unlk a6 * Restore caller's stack frame
rts
*
*****************************************************************
* WRITE_BUF writes the current record to disk and resets FILE buf
write_buf:
move.l 8(a6),d1 * Get FCB base address
add.l #dma_buf,d1 * Compute DMA buffer address
move.w #$001a,d0 * CP/M SET DMA ADDRESS Function
trap #2 * Setup DMA address
move.l 8(a6),a0 * Get FCB base address
clr.w dirty(a0) * Mark dirty flag as "clean"
clr.w curchr(a0) * Set current char pointer to 0
move.l a0,d1 * Get FCB address for CP/M
move.w #$0015,d0 * CP/M WRITE SEQUENTIAL Function
trap #2 * Write record
ext.w d0 * Convert CP/M return to our type
rts
*
*****************************************************************
* FGETC returns the next character from a file.
fgetc:
link a6,#0 * Establish stack frame
movem.l d1/a0,-(a7) * Save caller's registers
move.l 8(a6),a0 * Get FCB address
cmp.w #128,curchr(a0) * Do we need to read a record?
blt no_read * No, just get character
bsr get_rec * Read a record
tst.w d0 * Was there an error?
bmi fget_err * Yes, return error to caller
no_read:
move.w curchr(a0),d0 * Get current character counter
addq.w #1,curchr(a0) * Increment current char count
move.b dma_buf(a0,d0.w),d0 * Load next character
cmp.b #$1a,d0 * Is it EOF?
beq fget_err * Yes, return error.
ext.w d0 * Make into type "int".
bra fget_exit * And return...
fget_err:
move.w #-1,d0 * Indicate error
fget_exit:
movem.l (a7)+,d1/a0 * Restore caller's registers
unlk a6 * Restore caller's stack frame
rts
*
*****************************************************************
* GET_REC - reads next record sequentially. Local to FGETx.
get_rec:
move.l a0,d1 * Get FCB base address for CP/M
add.l #dma_buf,d1 * Compute DMA buffer address
move.w #$001a,d0 * CP/M SET DMA ADDRESS Function
trap #2 * Setup DMA address
move.l a0,d1 * Get FCB base address for CP/M
move.w #$0014,d0 * CP/M READ SEQUENTIAL function
trap #2 * Get the record
clr.w dirty(a0) * Mark record as "Clean"
clr.w curchr(a0) * Reset character counter
tst.b d0 * Look at return code
bne grec_err * Returned an error...
rts * Return success
grec_err:
move.w #-1,d0 * Load error return
rts * Return error
end